
#include "httpclient.h"

typedef struct __HTTP_REQUEST_DATA
{
    const std::string* pHost;
    const std::string* pMethod;
    const std::string* pRequest;
    std::list<std::string>* pHeader;
    std::string* pBody;
    HANDLE hEvent;
}HTTP_REQUEST_DATA;

static void http_connect_cb(PHTTP_LINKER pHttp, void* pUserData)
{
    HTTP_REQUEST_DATA* http_data = (HTTP_REQUEST_DATA *)pUserData;
    int size = 0;
    int offset = 0;
    char* buffer = 0;
    if (pHttp->pUrlInfo && pHttp->pUrlInfo->Path.len)
    {
        size = pHttp->pUrlInfo->Path.len +
            pHttp->pUrlInfo->Params.len +
            pHttp->pUrlInfo->Host.len + 256;
    }

    size += http_data->pRequest->length();
    buffer = (char*)malloc(size);

    if (pHttp->pUrlInfo && (pHttp->pUrlInfo->Path.len || pHttp->pUrlInfo->Params.len))
    {
        offset = wsprintfA(buffer, "%s /%s?%s HTTP/1.1\r\nhost:%s\r\n",
            http_data->pMethod->c_str(),
            pHttp->pUrlInfo->Path.len ? pHttp->pUrlInfo->Path.str : "",
            pHttp->pUrlInfo->Params.len ? pHttp->pUrlInfo->Params.str : "",
            pHttp->pUrlInfo->Host.str);
    }
    else
    {
        offset = wsprintfA(buffer, "%s / HTTP/1.1\r\nhost:%s\r\n", 
            http_data->pMethod->c_str(), http_data->pHost->c_str());
    }

    if (http_data->pRequest->length())
    {
        offset += wsprintfA(&buffer[offset],
            "content-length:%d\r\n\r\n%s",
            http_data->pRequest->length(),
            http_data->pRequest->c_str());
    }
    else
    {
        strcat(&buffer[offset], "\r\n");
        offset += 2;
    }
    
    fileio_write(pHttp->hHttp, buffer, offset);
}

static http_bool_t http_parser_header_callback(const char* strField, int nField,
    const char* strValue, int nValue, void* arg)
{
    PHTTP_LINKER pHttp = (PHTTP_LINKER)(arg);
    HTTP_REQUEST_DATA* http_data = (HTTP_REQUEST_DATA*)pHttp->pUserData;
    char strTmp[64] = { 0 };
    if (!strField || !strValue)
    {
        return TRUE;
    }

    std::string str;
    str.append(strField, (const size_t)nField);
    str.push_back(':');
    str.append(strValue, (const size_t)nValue);

    http_data->pHeader->push_back(str);

    return TRUE;
}

static void http_read_cb(PHTTP_LINKER pHttp, void* pUserData)
{
    int size = pHttp->nContentLenght;
    char* buffer = (char* )malloc(size + 1);

    size = http_read(pHttp, buffer, size);
    buffer[size] = '\0';
    HTTP_REQUEST_DATA* http_data = (HTTP_REQUEST_DATA*)pUserData;
    *http_data->pBody = buffer;

    http_separate_header(pHttp, http_parser_header_callback);

    SetEvent(http_data->hEvent);

}

static void http_write_cb(PHTTP_LINKER pHttp, void* pUserData)
{

}


BOOL http_request(HIOCPBASE hIocp, const std::string& host, const std::string& method, 
    const std::string& request, std::list<std::string>& response_header, std::string& response_body)
{
    PHTTP_LINKER pHttp = http_new_linker(hIocp, NULL);
    HTTP_REQUEST_DATA http_data;
    http_data.pHost = &host;
    http_data.pMethod = &method;
    http_data.pRequest = &request;
    http_data.pHeader = &response_header;
    http_data.pBody = &response_body;
    http_data.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    response_header.clear();
    response_body.clear();

    http_setcb(pHttp, http_read_cb, http_write_cb, NULL, &http_data);
    http_connect(pHttp, host.c_str(), http_connect_cb);

    WaitForSingleObject(http_data.hEvent, -1);

    http_close_linker(pHttp, 0);

    return TRUE;
}